#include <iostream>
#include <queue>
#include <pthread.h>

const int defaultMaxcap = 5;

template <class T>
class BlockQueue
{
public:
  BlockQueue(int maxcap = defaultMaxcap)
      : _maxcap(maxcap)
  {
    // _low_water = defaultMaxcap / 3;
    // _high_water = (defaultMaxcap * 2) / 3;
    pthread_mutex_init(&_mutex, nullptr);
    pthread_cond_init(&_c_cond, nullptr);
    pthread_cond_init(&_p_cond, nullptr);
  }

  T pop()
  {
    pthread_mutex_lock(&_mutex);

    while (_q.size() == 0)
    {
      pthread_cond_wait(&_c_cond, &_mutex);
    }

    T top = _q.front();
    _q.pop();

    // if (_q.size() < _low_water)
    pthread_cond_signal(&_p_cond);
    pthread_mutex_unlock(&_mutex);
    return top;
  }

  void push(T data)
  {
    pthread_mutex_lock(&_mutex);

    while (_q.size() == _maxcap)
    {
      pthread_cond_wait(&_p_cond, &_mutex);
    }
    _q.push(data);

    // if (_q.size() > _high_water)
    pthread_cond_signal(&_c_cond);
    pthread_mutex_unlock(&_mutex);
  }

  ~BlockQueue()
  {
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_c_cond);
    pthread_cond_destroy(&_p_cond);
  }

private:
  std::queue<T> _q;
  int _maxcap; // 队列最大值

  pthread_mutex_t _mutex; // 锁
  pthread_cond_t _c_cond; // 条件变量队列，因为生产消费两者解耦，应该要有两个不同的条件变量队列
  pthread_cond_t _p_cond;

  // int _low_water;
  // int _high_water;
};